package com.captjack.validator.aspect;

import com.captjack.validator.Result;
import com.captjack.validator.annotation.CommonParamValidator;
import com.captjack.validator.handler.ParamValidatorHandler;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.validation.ConstraintViolation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * 参数校验切面类
 *
 * @author Jack Sparrow
 * @version 1.0.0
 * @date 2018/5/26 21:22
 * package com.captjack.wechat.validator.aspect
 */
@Configuration
@Aspect
public class CommonParamValidatorAspect extends AbstractValidator {

    /**
     * 校验器
     */
    private final ParamValidatorHandler paramValidatorHandler;

    /**
     * 增强环绕通知
     *
     * @param proceedingJoinPoint 切面对象
     * @return 执行结果
     */
    @Around(value = "@annotation(com.captjack.validator.annotation.CommonParamValidator)")
    Object commonValidatorAround(ProceedingJoinPoint proceedingJoinPoint) {
        try {
            // 获取标注注解
            CommonParamValidator commonParamValidator = getMethodAnnotation(proceedingJoinPoint, CommonParamValidator.class);
            // 是否采用快速模式校验
            boolean isFast = commonParamValidator.isFast();
            // 获得切入目标对象
            Object target = proceedingJoinPoint.getThis();
            // 获得切入方法参数
            Object[] args = proceedingJoinPoint.getArgs();
            // 获得切入的方法
            Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
            // 校验基本数据类型方法参数
            Set<ConstraintViolation<Object>> validResult = paramValidatorHandler.validMethodParams(target, method, args, isFast);
            // 快速模式处理
            if (validResult.size() > 0 && isFast) {
                return renderValidatorResult(validResult);
            }
            // 需要剔除的参数索引 paramIndex 集合
            Set<Integer> paramIndex = new HashSet<Integer>(10) {{
                for (int index : commonParamValidator.excludeParamIndex()) {
                    add(index);
                }
            }};
            // 校验非基本数据类型的参数，在此剔除不需要校验的参数
            for (int i = 0; i < args.length && !paramIndex.contains(i); i++) {
                Object param = args[i];
                if (param != null && !paramValidatorHandler.isBaseDataType(param.getClass())) {
                    // 校验一次
                    Set<ConstraintViolation<Object>> set = paramValidatorHandler.validBeanParams(param, isFast);
                    // 如果有失败的情况，根据是否快速模式作出处理
                    if (set.size() > 0) {
                        // 快速模式直接返回错误结果
                        if (isFast) {
                            return renderValidatorResult(set);
                        } else {
                            validResult.addAll(set);
                        }
                    }
                }
            }
            // 走到此处时，要么校验成功，要么校验失败而且是非快速模式，如果失败，那么处理校验结果之后返回
            if (validResult.size() > 0) {
                return renderValidatorResult(validResult);
            }
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return Result.SERVER_EXCEPTION;
    }

    @Autowired
    public CommonParamValidatorAspect(ParamValidatorHandler paramValidatorHandler) {
        this.paramValidatorHandler = paramValidatorHandler;
    }

}
